
export const isBrowser = true
export const isDev = true
export const Message = window?.ElementPlus?.ElMessage
export const Confirm = window?.ElementPlus?.ElMessageBox.confirm
import {useUserInfoStore} from '@/store/userInfo.js'

export function getType(value) {
  return Object.prototype.toString
    .call(value)
    .match(/\s.+/g)[0]
    .replace(/\]/g, "")
    .replace(/\[/g, "")
    .replace(/\s+/g, "")
    .toLowerCase();
}

export function isToNumber(number) {
  return (
    getType(number) === "number" ||
    (number && getType(number) === "string" && !isNaN(+number))
  );
}

// 全局报错提示 Toast()
export async function Toast(msg) {
  const type = getType(msg);
  console.error("Toast-msg-----", type, msg);

  if (type === "error") {
    saveError(msg);
  }
  if (!isBrowser) return;
  if (["error", "string"].includes(type)) {
    Message({
      message: msg,
      type: "error",
      duration: 5000,
      center: true,
      // showClose: true,
    });
  }
}

function updateQueryStringParameter(key, value) {
  if (!isBrowser) return;
  let uri = window.location.href;
  // 先去除末尾的&
  if (uri[uri.length - 1] === "&") {
    uri = uri.slice(0, uri.length - 1);
  }
  if (value === null) {
    let re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
    uri = uri.replace(re, "$1");
    if (uri[uri.length - 1] === "?") {
      uri = uri.slice(0, uri.length - 1);
    }
    return uri;
  }
  if (!value) {
    return uri;
  }
  let re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
  let separator = uri.indexOf("?") !== -1 ? "&" : "?";
  if (uri.match(re)) {
    return uri.replace(re, "$1" + key + "=" + value + "$2");
  } else {
    return uri + separator + key + "=" + value;
  }
}
export function updateUrl(key, value) {
  if (!isBrowser) return;
  let newurl = updateQueryStringParameter(key, value);
  window.history.replaceState(
    {
      path: newurl,
    },
    "",
    newurl
  );
}

// 参数拼接
export function paramsJoin(params) {
  let str = "";
  for (let key in params) {
    str += key + "=" + params[key] + "&";
  }
  return str;
}

// 拼接参数
export function joinParams(url, params) {
  let str = "";
  for (const key in params) {
    str += key + "=" + params[key] + "&";
  }
  // 判断url是否有参数
  if (url.includes("?")) {
    url += "&" + str;
  } else {
    url += "?" + str;
  }

  // 判断最后一个字符是否是&
  if (url[url.length - 1] === "&") {
    url = url.substring(0, url.length - 1);
  }
  return url;
}

// 获取视频的本地地址
export function getObjectURL(file) {
  if (!isBrowser) return;
  var url = null;
  // 下面函数执行的效果是一样的，只是需要针对不同的浏览器执行不同的 js 函数而已
  if (window.createObjectURL !== undefined) {
    // basic
    url = window.createObjectURL(file);
  } else if (window.URL !== undefined) {
    // mozilla(firefox)
    url = window.URL.createObjectURL(file);
  } else if (window.webkitURL !== undefined) {
    // webkit or chrome
    url = window.webkitURL.createObjectURL(file);
  }
  return url;
}

// base64 => file
export function base64ToFile(base64Url, filename) {
  if (typeof base64Url !== "string" || !base64Url || !isBrowser) {
    return;
  }
  let arr = base64Url.split(",");
  let mime = arr[0].match(/:(.*?);/)[1];
  let bstr = window.atob(arr[1]);
  let n = bstr.length;
  let u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, { type: mime });
}

// 创建id
export function createId() {
  return "kl_" + Math.random().toString(36).substr(2);
}

// 将blob对象转换为base64
export function blobToBase64(blobFile) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(blobFile);
    reader.onload = (e) => {
      const res = e.target.result;
      resolve(res);
    };

    reader.onerror = (e) => {
      reject(e);
    };
  });
}

/**
 * 封装一个删除页面indexDB中的文件的方法
 * arr 需要动态加载的文件数组 示例 [{js:'aaa.js',isAppendHead:true},{css:'aaa.css'}]
 */

// 被销毁的加载
let delArr = [];
export async function delPageScript(arr) {
  if (!isArray(arr)) return;
  delArr = arr;
  // 这儿设置1s是为了不用去重，而且只是保证连续的两个页面使用到相同的插件不需要重复的删除与加载
  // await sleep(1000)
  delArr.forEach((item) => {
    // 找出data-url的节点
    let url = item.js ? item.js : item.css;
    if (!url) return;
    if (item.js) {
      let el = document.querySelector(`script[data-url="${url}"]`);
      // 删除
      if (el) {
        el.remove();
      }
      return;
    }

    if (item.css) {
      let el = document.querySelector(`link[data-url="${url}"]`);
      // 删除
      if (el) {
        el.remove();
      }
      return;
    }
  });
}

/**
 * getIndexDBJS()
 * 封装一个动态加载js，并会将请求回来的文件保存到indexDB中的方法
 * arr 需要动态加载的文件数组 示例 [{js:'aaa.js',isAppendHead:true},{css:'aaa.css'}]
 */
export function getIndexDBJS(arr, localforage, saveIndexdb = true) {
  if (!Array.isArray(arr)) {
    Toast("第一个参数必须为数组");
    return;
  }

  if (typeof localforage === "undefined") {
    const { localforageJS } = useUserInfoStore();
    localforage = localforageJS;
  }
  if (!localforage || !localforage.getItem) {
    return Promise.reject("localforage 不存在");
  }

  // 将文件注入到页面 type: js/css
  // loadScript()
  let delArr = [];
  function loadScript(url, row, ceate_time, remove = true, size = 0) {
    return new Promise(async (resolve, reject) => {
      let { isAppendHead, js, css } = row;
      let type = css ? "css" : "js";
      if (!url) {
        return reject("failed-url没有配置");
      }
      // 防止重复加载,没有检查插件是否加载成功，导致并发同一个时，这儿会出错
      let haveLoadDom = "";
      if (type === "js") {
        haveLoadDom = document.querySelector(`script[data-url="${js}"]`);
      } else if (type === "css") {
        haveLoadDom = document.querySelector(`link[data-url="${css}"]`);
      }
      if (haveLoadDom) {
        // 先检查是否已经加载成功
        if (haveLoadDom.getAttribute("load_type") === "success") {
          return resolve("successful");
        }
        haveLoadDom.addEventListener("load", () => {
          resolve("successful");
        });
        haveLoadDom.addEventListener("error", () => {
          resolve("failed");
        });
        return;
      }
      // 将url base64数据转成内存地址
      if (typeof url === "string" && url.startsWith("data:")) {
        url = getObjectURL(await base64ToFile(url));
      }

      let scriptDom = "";
      if (type === "js") {
        scriptDom = document.createElement("script");
        scriptDom.setAttribute("src", url);
        scriptDom.setAttribute("data-url", js);
        scriptDom.setAttribute("type", "text/javascript");
        scriptDom.setAttribute("ceate_time", ceate_time);
        scriptDom.setAttribute("load_indexdb", remove);
        scriptDom.setAttribute("size", size);
      }

      if (type === "css") {
        scriptDom = document.createElement("link");
        scriptDom.setAttribute("href", url);
        scriptDom.setAttribute("data-url", css);
        scriptDom.setAttribute("rel", "stylesheet");
        scriptDom.setAttribute("ceate_time", ceate_time);
        scriptDom.setAttribute("load_indexdb", remove);
        scriptDom.setAttribute("size", size);
      }

      // 对于css默认 isAppendHead 为true
      if (typeof isAppendHead === "undefined") {
        isAppendHead = type === "css" ? true : false;
      }

      document[isAppendHead ? "head" : "body"].appendChild(scriptDom);

      scriptDom.addEventListener("load", () => {
        // 设置加载完成，防止重复监听
        scriptDom.setAttribute("load_type", "success");
        resolve("successful");
      });

      scriptDom.addEventListener("error", () => {
        resolve("failed");
      });
    });
  }
  let arr1 = [];
  arr.forEach((element) => {
    const { loading = false, cache = true, version = "1.0" } = element;
    let url = element.js ? element.js : element.css;
    if (!cache) {
      arr1.push(loadScript(url, element, Date.now(), element.remove));
      return;
    }
    // 先判断即将移除是否是新增的
    if (delArr.some((item) => item.css === url || item.js === url)) {
      // delArr 移除这个
      delArr = delArr.filter((item) => item.css !== url && item.js !== url);
      return arr1.push(Promise.resolve(true));
    }
    arr1.push(
      localforage
        .getItem(url)
        .then(async (res) => {
          if (res) {
            const { indexVersion = "1.0" } = res;
            if (indexVersion == version) {
              // 版本一致，使用缓存
              await loadScript(
                res.file,
                element,
                res.ceate_time,
                element.remove,
                res.size
              );
              return true;
            }
          }

          // 没有命中缓存
          let klLoad = null;
          if (loading) {
            klLoad = klLoading({
              msg: "大文件首次加载...",
            });
          }

          await loadScript(url, element, Date.now(), element.remove);
          if (loading && klLoad) {
            klLoad.close()
          }
          if (saveIndexdb === false) return true;
          fetch(url)
            .then((response) => response.blob())
            .then(async (res) => {
              const { size = 0 } = res || {};
              try {
                let file = await blobToBase64(res);
                // 保存
                localforage.setItem(url, {
                  ceate_time: Date.now(),
                  size,
                  file,
                  remove: element.remove || false,
                  indexVersion: version,
                });

                // 获取对应的节点设置size
                const dom = document.querySelector(`[data-url="${url}"]`);
                dom.setAttribute("size", size);
              } catch (err) {
                return false;
              }
            })
            .catch((err) => {
              return false;
            });
        })
        .catch((err) => {
          console.log("getData-err", err);
        })
    );
  });

  // 将所有的注入返回
  return Promise.all(arr1);
}

/**
 * 封装一个动态加载图片，并会将请求回来的文件保存到indexDB中的方法
 * imgs 参数格式 1、字符串 2、对象
 * ***/
export async function getIndexDBIMJ(imgs, localforage, auto = false) {
  if (!localforage) {
    const { localforageJS } = useUserInfoStore();
    localforage = localforageJS;
  }
  let type = typeof imgs;

  if (type === "string") {
    let res = await localforage.getItem(imgs);

    if (res) {
      return res;
    }
    fetch(imgs)
      .then((response) => response.blob())
      .then(async (res) => {
        try {
          let file = await blobToBase64(res);
          localforage.setItem(imgs, file);
        } catch (e) {}
      });
    return imgs;
  }

  let imgsArr = Object.keys(imgs);
  imgsArr.forEach(async (item) => {
    const url = imgs[item];
    let res = await localforage.getItem(url);
    if (res) {
      if (auto) {
        this[item] = url;
      }
      return;
    }
    if (auto) {
      this[item] = url;
    }

    fetch(url)
      .then((response) => response.blob())
      .then(async (res) => {
        try {
          let file = await blobToBase64(res);
          localforage.setItem(url, file);
        } catch (e) {}
      });
  });
}

export function sleep(time = 100) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, time);
  });
}

/**
 * 找出链接中的参数
 * @author wxj
 * @datetime 2022-03-10 16:15:00
 * @param {string} queryString - 一个查询字符串.
 * @returns {object} - 返回一个对象.
 */
export function qsParse(queryString) {
  if (typeof queryString !== "string") {
    return {};
  }
  let arr = queryString.match(/[^&=#?]+=[^&=#?]+/g);
  if (arr === null) {
    return {};
  }
  arr = arr.map((item) => {
    return { key: item.split("=")[0], value: item.split("=")[1] };
  });
  // 重新组装数据
  let result = {};
  arr.forEach((item) => {
    let { key, value } = item;
    let allKeys = key.match(/[^\[\]]+/g);
    // 连续创建对象
    if (allKeys.length === 1) {
      // 存在一个key
      result[key] = decodeURIComponent(value);
    } else {
      // 递归创建对象或数组
      let lastValue = result; // 存取上次递归得到的对象或数组
      let len = allKeys.length;
      for (let i = 0; i < len - 1; i++) {
        let current = allKeys[i];
        let next = allKeys[i + 1];
        if (lastValue[current] === undefined) {
          lastValue[current] = isNaN(next) ? {} : [];
          lastValue = lastValue[current];
        }
        if (lastValue[current]) {
          lastValue = lastValue[current];
        }
      }
      let lastKey = allKeys[len - 1];
      lastValue[lastKey] = decodeURIComponent(value);
    }
  });
  return result;
}

/**
 * 将对象生成查询字符串.
 * @author wxj
 * @datetime 2022-03-10 16:15:00
 * @param {object} obj - 一个对象.
 * @returns {string} - 返回一个查询字符串.
 */
export function qsStringify(obj) {
  let result = []; //用于存放所有键值对字符串
  if (!isObject(obj)) {
    return "";
  }
  // 遍历数组或对象
  let traverse = function (o, lastKey = "") {
    if (getType(o) === "object") {
      Object.keys(o).forEach((key) => {
        let item = o[key];
        let subType = getType(item);
        if (["object", "array"].includes(subType)) {
          let keyValue = lastKey ? `${lastKey}[${key}]` : `${key}`;
          traverse(item, keyValue);
        } else {
          if (["undefined", "null", "function"].includes(subType)) {
            item = "";
          }
          let keyValue = lastKey
            ? `${lastKey}[${key}]=${encodeURIComponent(item)}`
            : `${key}=${encodeURIComponent(item)}`;
          result.push(keyValue);
        }
      });
    }
    if (getType(o) === "array") {
      o.forEach((item, index) => {
        let subType = getType(item);
        if (["object", "array"].includes(subType)) {
          let keyValue = `${lastKey}[${index}]`;
          traverse(item, keyValue);
        } else {
          if (["undefined", "null", "function"].includes(subType)) {
            item = "";
          }
          let keyValue = `${lastKey}[${index}]=${encodeURIComponent(item)}`;
          result.push(keyValue);
        }
      });
    }
  };
  traverse(obj);
  return result.join("&");
}

/**
 * 页面跳转函数goTo()
 * @author wxj
 * @datetime 2022年3月14日11:30:07
 * @param {string} url - 跳转地址.
 * @param {object} options - 配置项：{query: {}, delay: 1000,replace: true|false, target: _blank|_self,openNew:false}.
 * @returns {object} - 返回一个对象.
 */
export function goTo(url, options = {}) {
  const urlType = getType(url);
  const {useRouter} = VueRouter
  const router = useRouter();

  if (urlType === "number") {
    router.go(url);
    return;
  }
  if (!url || urlType !== "string") {
    Toast("url参数错误");
    return;
  }
  if (!isObject(options)) {
    Toast("options参数错误");
    return;
  }
  let { query = {}, replace = false, target = "_self" } = options;

  // 链接中的参数
  let urlIncludeParams = qsParse(url);
  // 组装query中的参数及去掉参数中值为undefined
  query = qsParse(qsStringify(query));
  // 合并参数
  let combineParams = { ...urlIncludeParams, ...query };
  let queryString = qsStringify(combineParams);
  // 重新拼接链接
  let jumpUrl = url.split("?")[0] + (queryString ? "?" + queryString : "");

  let arr = ["http", "https"];
  // 判断是否是完整的链接
  let isFlag = arr.some((item) => jumpUrl.startsWith(item));

  if (target === "_blank") {
    if (isFlag) {
      window.open(jumpUrl, "_blank");
      return;
    }
    let routeUrl = router.resolve({
      path: jumpUrl,
      query: combineParams,
    });
    window.open(routeUrl.href, "_blank");
    return;
  }

  if (replace) {
    isFlag ? location.replace(jumpUrl) : router.replace(jumpUrl);
    return;
  }
  isFlag ? (location.href = jumpUrl) : router.push(jumpUrl);
}

// 是否是对象
export function isObject(obj) {
  return Object.prototype.toString.call(obj) === "[object Object]";
}

// 是否是数组
export function isArray(arr) {
  return Object.prototype.toString.call(arr) === "[object Array]";
}

/**
 * 取出Local方法
 * name 传入的名字
 * defaultType 默认类型
 * expire_time 过期时间 默认-1不过期
 * **/
export function getLocalStorage(name, defaultType = null, expire_time = -1) {
  if (getType(expire_time) !== "number") {
    Toast("过期时间必须是数字类型");
    return;
  }
  if (getType(name) !== "string" || !name) {
    Toast("请传入获取的对象名");
    return;
  }

  if (defaultType === null) {
    Toast("请传入默认获取类型，防止类型错误");
    return;
  }
  let res = localStorage.getItem(getStoreName(name));
  if (!res) {
    return defaultType;
  }
  let current_time = Date.now();
  let result = {};
  try {
    result = JSON.parse(res);
  } catch (e) {}
  let { save_time = 0, data } = result;
  if (expire_time >= 0 && save_time && current_time - save_time > expire_time) {
    localStorage.removeItem(getStoreName(name));
    return defaultType;
  }
  return getType(data) === getType(defaultType) ? data : defaultType;
}

// 判断是否存在
export function isExist(data) {
  return ![null, undefined].includes(data);
}

// 存储
export function setLocalStorage(name, data) {
  if (!isExist(name) || !isExist(data)) {
    Toast("请传入保存的对象名或数据");
    return;
  }
  let result = JSON.stringify({
    save_time: Date.now(),
    data,
  });
  try {
    localStorage.setItem(getStoreName(name), result);
  } catch (e) {
    // 通常来说这里是因为存储空间满了，需要清除一些数据
    // 包含下面数组的key，将会被清除掉
    let keysKeyword = ["question"];
    //如果出问题了，清除掉所有缓存的试题数据，并重新写入
    let examStorages = Object.keys(localStorage).filter((ckey) =>
      keysKeyword.some((item) => ckey.includes(item))
    );

    examStorages.forEach((ckey) => {
      localStorage.removeItem(ckey);
    });
    localStorage.setItem(getStoreName(name), result);
  }
}

//  清除的
export function removeLocalStorage(name) {
  if (!name || getType(name) !== "string") {
    Toast("请传入删除的对象名");
    return;
  }
  localStorage.removeItem(getStoreName(name));
}

// 存储 和 取出 清除的Session方法
export function getSessionStorage(name) {
  if (getType(name) !== "string" || !name) return null;
  let res = sessionStorage.getItem(name);
  if (!res) return null;
  return JSON.parse(res);
}

export function setSessionStorage(name, data) {
  if (!name || !isExist(data)) {
    Toast("请传入保存的对象名或数据");
    return;
  }
  sessionStorage.setItem(name, JSON.stringify(data));
}

export function deepCopy(obj, cache = new WeakMap()) {
  // 处理非对象和特殊类型
  if (obj === null || typeof obj !== "object") return obj;

  // 处理循环引用
  if (cache.has(obj)) return cache.get(obj);

  // 处理特殊对象类型
  switch (Object.prototype.toString.call(obj)) {
    case "[object Date]":
      return new Date(obj.getTime());
    case "[object RegExp]":
      return new RegExp(obj);
    case "[object Function]":
      // 保持函数引用，如需完全复制可使用 eval(obj.toString()) 但存在安全隐患
      return obj;
    case "[object Map]":
      return new Map(Array.from(obj, ([k, v]) => [deepCopy(k), deepCopy(v)]));
    case "[object Set]":
      return new Set(Array.from(obj, (v) => deepCopy(v)));
  }

  // 创建空对象并缓存
  const copy = Array.isArray(obj)
    ? []
    : Object.create(Object.getPrototypeOf(obj));
  cache.set(obj, copy);

  // 递归拷贝属性
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key], cache);
    }
  }

  // 处理Symbol类型属性
  const symbolKeys = Object.getOwnPropertySymbols(obj);
  for (const symKey of symbolKeys) {
    copy[symKey] = deepCopy(obj[symKey], cache);
  }

  return copy;
}

export function selectFilterOption(inputValue, option) {
  return option.label.toLowerCase().includes(inputValue.trim().toLowerCase());
}

export function addZero(num) {
  return num < 10 ? "0" + num : num;
}
// 时间处理函数 klDateFormat()
export function klDateFormat(date, type = "yyyy/MM/dd hh:mm:ss") {
  // 传入的格式为string: yyyy/MM/dd hh:mm:ss  array: '[yyyy,MM,dd,hh,mm,ss]'
  // date 必须是标准时间戳 type为返回类型 string 或者 array
  if (!isExist(date) || date === "") {
    return date;
  }

  if (!isToNumber(date)) {
    if (isDev) {
      console.error("请传入标准时间戳");
    }
    return date;
  }

  date = Number(date);

  let dateObj = new Date(date);
  let year = dateObj.getFullYear();
  let month = dateObj.getMonth() + 1;
  let day = dateObj.getDate();
  let hour = dateObj.getHours();
  let minute = dateObj.getMinutes();
  let second = dateObj.getSeconds();

  let yyyy = year;
  let MM = addZero(month);
  let M = month;
  let dd = addZero(day);
  let d = day;
  let hh = addZero(hour);
  let h = hour;
  let mm = addZero(minute);
  let m = minute;
  let ss = addZero(second);
  let s = second;

  let all = {
    yyyy,
    MM,
    M,
    dd,
    d,
    hh,
    h,
    mm,
    m,
    ss,
    s,
  };

  if (type.includes("[") && type.includes("]")) {
    let arr = type.replace("[", "").replace("]", "").split(",");
    let result = [];
    arr.forEach((item) => {
      result.push(eval(item));
    });
    return result;
  }
  // 将传入的参数分开
  let join_str = "";
  let arr = [];
  if (type.includes(" ")) {
    arr = type.split(" ");
    join_str = " ";
  } else {
    arr.push(type);
  }
  let result = "";
  arr.forEach((item) => {
    if (item.includes("/")) {
      let arr2 = item.split("/");
      arr2.forEach((item2, index) => {
        if (index == arr2.length - 1) {
          result += all[item2];
        } else {
          result += all[item2] + "/";
        }
      });
      result += join_str;
    }
    if (item.includes("-")) {
      let arr2 = item.split("-");
      arr2.forEach((item2, index) => {
        if (index == arr2.length - 1) {
          result += all[item2];
        } else {
          result += all[item2] + "-";
        }
      });
      result += join_str;
    }

    if (item.includes(":")) {
      let arr2 = item.split(":");
      arr2.forEach((item2, index) => {
        if (index == arr2.length - 1) {
          result += all[item2];
        } else {
          result += all[item2] + ":";
        }
      });
    }
  });
  return result;
}

// 处理参数
// obj 需要处理的对象
// limit_arr 只允许返回的字段数组
// obj 的属性必须是 字符串类型 不允许是number类型
export function filterQuery(obj = {}, limit_arr = [], deep = false) {
  if (!limit_arr.length) {
    limit_arr = Object.keys(obj);
  }
  let result = {};
  if (getType(obj) !== "object" || getType(limit_arr) !== "array") return {};
  for (const key in obj) {
    if (key && obj.hasOwnProperty(key) && limit_arr.includes(key)) {
      let keyVal = obj[key];
      let type = getType(keyVal);

      if (type === "boolean") {
        result[key] = keyVal;
      }
      if (type === "string" && keyVal) {
        result[key] = keyVal;
      }

      if (type === "number") {
        result[key] = keyVal;
      }

      if (type === "array" && keyVal.length) {
        result[key] = keyVal;
      }

      if (type === "object" && Object.keys(keyVal).length) {
        if (deep) {
          result[key] = filterQuery(keyVal, limit_arr);
          if (!Object.keys(result[key]).length) {
            delete result[key];
          }
        } else {
          result[key] = keyVal;
        }
      }
    }
  }

  return result;
}

/**
 * description 判断一个数组是否长度大于0
 * @param {Array} arr 需要判断的数组
 * @param {Boolean,String} msg 是否提示信息
 */
export function isArrayLength(arr, msg = false) {
  let arrType = getType(arr);
  let messageType = getType(msg);
  let isFlag = arrType === "array" && arr.length > 0;
  if (!isFlag) {
    if (msg === true) {
      Toast("请传入数组并且长度大于0");
    } else if (messageType === "string" && msg) {
      Toast(msg);
    }
  }
  return isFlag;
}

// 自动补全图片路径
export function parseResourceUrl(url) {
  if (!url || typeof url !== "string") {
    return "https://image.zlketang.com/public/news/others/imgs/book.jpg";
  }

  // 完整链接
  if (
    url.includes("https://") ||
    url.includes("http://") ||
    url.includes("127.0.0.1")
  ) {
    return url;
  }

  // 相对路径
  url = url.replace(/\\/g, "/");
  if (url.slice(0, 1) === "/") {
    return BASE_URL + url;
  }
  return BASE_URL + "/" + url;
}

// 图片压缩
export function compressImg(file, qualitys) {
  // 文件大小kb
  let fileSize = parseInt((file.size / 1024).toFixed(2));
  if (!qualitys) {
    qualitys = 1;
    if (fileSize > 200) {
      qualitys = 0.98;
    }
    if (fileSize > 500) {
      qualitys = 0.95;
    }
    if (fileSize > 1024) {
      qualitys = 0.92;
    }
    if (fileSize > 2 * 1024) {
      qualitys = 0.9;
    }
    if (fileSize > 5 * 1024) {
      qualitys = 0.85;
    }
  }

  if (file[0]) {
    return Promise.all(Array.from(file).map((e) => compressImg(e, qualitys))); // 如果是 file 数组返回 Promise 数组
  } else {
    return new Promise((resolve) => {
      if (qualitys == 1) {
        // 获取图片宽高
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = (e) => {
          const img = new Image();
          img.src = e.target.result;
          img.onload = () => {
            resolve({
              file: file,
              newWidth: img.width,
              newHeight: img.height,
            });
          };
        };
      } else {
        const reader = new FileReader(); // 创建 FileReader
        reader.onload = ({ target: { result: src } }) => {
          const image = new Image(); // 创建 img 元素
          image.onload = async () => {
            const canvas = document.createElement("canvas"); // 创建 canvas 元素
            const context = canvas.getContext("2d");
            var targetWidth = image.width;
            var targetHeight = image.height;
            var originWidth = image.width;
            var originHeight = image.height;
            if (
              1 * 1024 <= parseInt((file.size / 1024).toFixed(2)) &&
              parseInt((file.size / 1024).toFixed(2)) <= 10 * 1024
            ) {
              var maxWidth = 1600;
              var maxHeight = 1600;
              targetWidth = originWidth;
              targetHeight = originHeight;
              // 图片尺寸超过的限制
              if (originWidth > maxWidth || originHeight > maxHeight) {
                if (originWidth / originHeight > maxWidth / maxHeight) {
                  // 更宽，按照宽度限定尺寸
                  targetWidth = maxWidth;
                  targetHeight = Math.round(
                    maxWidth * (originHeight / originWidth)
                  );
                } else {
                  targetHeight = maxHeight;
                  targetWidth = Math.round(
                    maxHeight * (originWidth / originHeight)
                  );
                }
              }
            }
            if (
              10 * 1024 <= parseInt((file.size / 1024).toFixed(2)) &&
              parseInt((file.size / 1024).toFixed(2)) <= 20 * 1024
            ) {
              maxWidth = 1400;
              maxHeight = 1400;
              targetWidth = originWidth;
              targetHeight = originHeight;
              // 图片尺寸超过的限制
              if (originWidth > maxWidth || originHeight > maxHeight) {
                if (originWidth / originHeight > maxWidth / maxHeight) {
                  // 更宽，按照宽度限定尺寸
                  targetWidth = maxWidth;
                  targetHeight = Math.round(
                    maxWidth * (originHeight / originWidth)
                  );
                } else {
                  targetHeight = maxHeight;
                  targetWidth = Math.round(
                    maxHeight * (originWidth / originHeight)
                  );
                }
              }
            }
            canvas.width = targetWidth;
            canvas.height = targetHeight;
            context.clearRect(0, 0, targetWidth, targetHeight);
            context.drawImage(image, 0, 0, targetWidth, targetHeight); // 绘制 canvas
            const canvasURL = canvas.toDataURL("image/jpeg", qualitys);
            const buffer = atob(canvasURL.split(",")[1]);
            let length = buffer.length;
            const bufferArray = new Uint8Array(new ArrayBuffer(length));
            while (length--) {
              bufferArray[length] = buffer.charCodeAt(length);
            }
            const miniFile = new File([bufferArray], file.name, {
              type: "image/jpeg",
            });
            resolve({
              file: miniFile,
              origin: file,
              beforeSrc: src,
              afterSrc: canvasURL,
              newWidth: targetWidth,
              newHeight: targetHeight,
              beforeKB: Number((file.size / 1024).toFixed(2)),
              afterKB: Number((miniFile.size / 1024).toFixed(2)),
            });
          };
          image.src = src;
        };
        reader.readAsDataURL(file);
      }
    });
  }
}

// 复制字符串 - 兼容复制\n
export function copyText(text) {
  return new Promise((res, rej) => {
    let isSuccess = false;
    let el_div = document.createElement("div");
    let className = "zl" + Math.random().toString(36).substr(2);
    el_div.className = className;
    el_div.innerText = text;
    el_div.style.opacity = "0";
    document.body.appendChild(el_div);
    if (navigator.userAgent.match(/(iPhone|iPod|iPad);?/i)) {
      /*ios复制*/
      window.getSelection().removeAllRanges(); //将页面所有的文本区域都从选区中移除
      let range = document.createRange(); //创建一个文本区域
      range.selectNode(el_div); //将我们的所选节点添加到文本区域中
      /*上面经过测试不可以range.selectNode(node)*/
      window.getSelection().addRange(range); //将文本区域添加至选区中
      isSuccess = document.execCommand("Copy"); //执行浏览器的复制命令
      window.getSelection().removeAllRanges(); //最后再移除选区中的所有文本区域
    } else {
      /*下面是其他浏览器的复制*/
      let range = document.createRange(); //创建一个文本区域
      range.selectNodeContents(el_div); //将我们的所选节点添加到文本区域中
      /*上面经过测试不可以range.selectNode(node)*/
      window.getSelection().removeAllRanges(); //将页面所有的文本区域都从选区中移除
      window.getSelection().addRange(range); //将文本区域添加至选区中
      isSuccess = document.execCommand("Copy"); //执行浏览器的复制命令
      window.getSelection().removeAllRanges(); //最后再移除选区中的所有文本区域
    }
    // 移除节点
    document.body.removeChild(el_div);
    isSuccess ? res("复制成功") : rej("复制失败");
  });
}

// 单击事件模拟双击事件
let mouseX = 0;
let mouseY = 0;

if (isBrowser) {
  window.addEventListener("mousemove", (event) => {
    mouseX = event.clientX;
    mouseY = event.clientY;
  });
}

export function dbClick(minTime = 500) {
  const dbSessionKey = "getDbClickObj_zl_2020";
  return new Promise((res) => {
    let number = 0;
    let timer = null;
    let getDbClickObj = sessionStorage.getItem(dbSessionKey);

    function saveDbClickObj() {
      sessionStorage.setItem(
        dbSessionKey,
        JSON.stringify({
          number,
          timer,
          mouseX,
          mouseY,
        })
      );
    }

    function clearTimer() {
      clearTimeout(timer);
      timer = null;
    }

    function createTimer() {
      timer = setTimeout(() => {
        number = 0;
        saveDbClickObj();
      }, minTime);
    }
    if (getDbClickObj) {
      try {
        getDbClickObj = JSON.parse(getDbClickObj);
      } catch (err) {
        getDbClickObj = {};
      }

      number = getDbClickObj.number || 0;
      timer = getDbClickObj.timer || null;
      // 判断位置是否有偏移
      if (
        Math.abs(getDbClickObj.mouseX - mouseX) > 20 ||
        Math.abs(getDbClickObj.mouseY - mouseY) > 20
      ) {
        number = 1;
        clearTimer();
        saveDbClickObj();
        createTimer();
        return;
      }
    }
    number++;
    // 第一次点击，设置定时器，重置number
    createTimer();

    if (number == 2) {
      // 是双击
      res(true);
      number = 0;
      clearTimer();
      sessionStorage.removeItem(dbSessionKey);
      return;
    }

    saveDbClickObj();
  });
}

// 图片预览
export function prevewImg(
  el,
  { transitionTime = 0.5, flyImgClass = "", zIndex = 1000 } = {},
  callback
) {
  // 批量设置样式
  function setStyle(el, style) {
    for (let key in style) {
      el.style[key] = style[key];
    }
  }

  if (typeof el === "string") {
    el = document.querySelector(el);
  }
  // 获取
  if (!el) return;
  // 获取图片链接
  let imgUrl = el.getAttribute("src");
  if (!imgUrl) return;
  // 保留原来的样式
  let { visibility } = el.style;
  el.style.visibility = "hidden";
  // 获取el的宽高
  let { width: width_old, height: height_old } = window.getComputedStyle(el);
  // 获取el在可视区的位置
  let { top, left } = el.getBoundingClientRect();
  // 获取可视区宽高
  let { clientHeight, clientWidth } = document.documentElement;
  // 创建一个新的img
  let newImg = document.createElement("img");
  newImg.src = imgUrl;
  let defaultClass = "kl-prevew-img";
  newImg.className = flyImgClass
    ? defaultClass + "" + flyImgClass
    : defaultClass;

  // 给预览图片设置初始的位置及大小（原来的图片大小与位置）
  setStyle(newImg, {
    width: width_old,
    height: height_old,
    position: "fixed",
    top: 0 + "px",
    left: 0 + "px",
    transform: `translate(${left}px, ${top}px)`,
    zIndex,
    transition: `all ${transitionTime}s`,
    borderRadius: "5px",
    boxShadow: "0 0 5px #999",
    cursor: "zoom-out",
    objectFit: "cover",
  });

  // append到body
  document.body.appendChild(newImg);
  // 获取图片的真实宽高
  let img = new Image();
  img.src = imgUrl;
  img.onload = () => {
    // 创建蒙层
    let mask = document.createElement("div");
    setStyle(mask, {
      position: "fixed",
      top: 0,
      left: 0,
      width: "100%",
      height: "100%",
      zIndex: zIndex - 1,
      background: "rgba(0,0,0,0.5)",
      cursor: "zoom-out",
      transition: `all ${transitionTime}s`,
    });
    document.body.appendChild(mask);
    let { width, height } = img;
    // 限制宽高不能超出可视区的95%，且图片不能变形，需要完整展示
    let maxWidth = clientWidth * 0.95;
    let maxHeight = clientHeight * 0.95;
    let ratio = width / height;
    if (width > maxWidth) {
      width = maxWidth;
      height = width / ratio;
    }
    if (height > maxHeight) {
      height = maxHeight;
      width = height * ratio;
    }
    // 计算新的位置
    let newTop = (clientHeight - parseInt(height)) / 2;
    let newLeft = (clientWidth - parseInt(width)) / 2;

    // 给预览图片设置新的居中位置
    setStyle(newImg, {
      // top: newTop + 'px',
      // left: newLeft + 'px',
      transform: `translate(${newLeft}px, ${newTop}px)`,
      width: width + "px",
      height: height + "px",
    });

    // 防止重复触发
    let isFlag = false;
    // 关闭预览相关方法
    let timer = setTimeout(() => {
      mask.addEventListener("click", closePrevew);
      newImg.addEventListener("click", closePrevew);
      // 鼠标滚轮事件触发也需要关闭
      document.addEventListener("mousewheel", closePrevew);
      document.addEventListener("DOMMouseScroll", closePrevew);
    }, transitionTime * 1000);

    function closePrevew() {
      if (isFlag) return;
      isFlag = true;
      // 使用动画移除蒙层及图片
      mask.style.opacity = 0;
      // 图片要移动到原来的位置
      setStyle(newImg, {
        // top: top + 'px',
        // left: left + 'px',
        transform: `translate(${left}px, ${top}px)`,
        width: width_old,
        height: height_old,
        borderRadius: "5px",
        boxShadow: "0 0 5px #f0f0f0",
      });

      timer = setTimeout(() => {
        // 移除蒙层
        document.body.removeChild(mask);
        document.body.removeChild(newImg);
        // 图片显示
        el.style.visibility = visibility;
        clearTimeout(timer);
        timer = null;
        callback && callback("finished");
      }, transitionTime * 1000);
    }
  };
  img.onerror = () => {
    // 直接关闭
    document.body.removeChild(newImg);
  };
}


function getStoreName(name){
  const { _id = '' } = useUserInfoStore()?.userInfo || {}
  return `${_id}_${name}`
}

/**
 * indexdb存储函数getStore()
 * name 存储名称
 * defaultType 获取不到数据时的默认值,这个默认值类型必须和实际值保持一致
 * local 存储类型，normal为正常存储，localforageAPI为使用localforageAPI存储
 * expire_time 缓存时长 ms
 * update_save_time 是否更新保存时间 只有  expire_time大于0时生效
 * **/
export async function getStore(
  name,
  defaultValue = {},
  { local = "normal", expire_time = -1,update_save_time = false } = {}
) {
  let result = null;
  try {
    if (getType(expire_time) !== "number") {
      Toast("过期时间必须是数字类型");
      return;
    }

    if (local === "localforageAPI") {
      const { localforageAPI } = useUserInfoStore();

      if (!localforageAPI || !localforageAPI.getItem) {
        return Promise.reject("localforageAPI is not defined");
      }
      result = (await localforageAPI.getItem(getStoreName(name))) || {};
    }

    if (local === "normal") {
      result = (await localforage.getItem(getStoreName(name))) || {};
    }

    const defaultType = getType(defaultValue);
    const { save_time = 0, data } = result;

    if (getType(data) !== defaultType) {
      // 与预期数据类型不同
      return defaultValue;
    }

 const currrntTime = Date.now()
    if (expire_time >= 0 && save_time && currrntTime - save_time > expire_time) {
      // 过期了
      return defaultValue;
    }

    if(update_save_time){
      setStore(name, data, { local });
    }

    return data;
  } catch (e) {
    Toast(e);
    return Promise.reject(e);
  }
}

/**
 * indexdb存储函数setStore()
 * name 存储名称
 * data 存储数据
 * local 存储类型，normal为正常存储，localforageAPI为使用localforageAPI存储
 * **/
export async function setStore(name, data, { local = "normal" } = {}) {
  try {
    const saveData = {
      save_time: Date.now(),
      data,
    };
    if (local === "localforageAPI") {
      const { localforageAPI } = useUserInfoStore();
      if (!localforageAPI || !localforageAPI.getItem) {
        return Promise.reject("localforageAPI is not defined");
      }
      await localforageAPI.setItem(getStoreName(name), saveData);
    }

    if (local === "normal") {
      await localforage.setItem(getStoreName(name), saveData);
    }
  } catch (e) {
    return Promise.reject(e);
  }
}

export async function removeStore(name, { local = "normal" } = {}) {
  if (local === "localforageAPI") {
    const { localforageAPI } = useUserInfoStore();
    if (!localforageAPI || !localforageAPI.getItem) {
      return Promise.reject("localforageAPI is not defined");
    }
  }
  try {
    if (local === "localforageAPI") {
      await localforageAPI.removeItem(getStoreName(name));
    }
    if (local === "normal") {
      await localforage.removeItem(getStoreName(name));
    }
  } catch (e) {
    return Promise.reject(e);
  }
}

/**
 * 生成一张canvas图片
 * isBase64 直接生成file的本地地址
 * bgImg 背景图片地址
 */
// http://47.108.195.190:5000/netdist/d0c628394d74c37b8bc61dfb714b3144-1718940105199~1~.jpg
export function createCanvasImg(
  {
    width = 0,
    height = 0,
    fontSize = 30,
    fontContent = "",
    fontColor = "",
    bgImg = "",
    isBase64 = false,
  } = (options = {})
) {
  return new Promise(async (resolve, reject) => {
    if (!width || !height) reject("请传入宽高");
    if (!fontContent) {
      fontContent = new Date().toLocaleDateString(); // 默认今天的日期
    }
    if (!fontColor) {
      fontColor = createColor(); // 随机生成一个颜色
    }

    // 对于不同分辨率的屏幕，设置画布的大小
    const devicePixelRatioa = window.devicePixelRatio || 1;
    // const devicePixelRatioa = 1
    width = width * devicePixelRatioa;
    height = height * devicePixelRatioa;
    fontSize = fontSize * devicePixelRatioa;
    let canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    let ctx = canvas.getContext("2d");

    function createText() {
      ctx.font = `${fontSize}px Arial`;
      ctx.fillStyle = fontColor;
      ctx.textBaseline = "top";
      ctx.textAlign = "left";
      let y = height / 2;
      let textHeight = fontSize * devicePixelRatioa;
      let textY = y - textHeight / 2;
      ctx.shadowColor = "black";
      ctx.shadowBlur = 2 * devicePixelRatioa; // 阴影的模糊度
      ctx.shadowOffsetY = 1 * devicePixelRatioa; // 阴影在垂直方向上的偏移
      ctx.fillText(fontContent, 10 * devicePixelRatioa, textY);
    }

    async function createImg() {
      let dataURL = canvas.toDataURL("image/jpeg");
      if (!isBase64) {
        let file = await dataURLtoFile(dataURL, createId());
        let url = getObjectURL(file.file_);
        resolve(url);
      } else {
        resolve(dataURL);
      }
    }

    function createColor() {
      return "#" + Math.floor(Math.random() * 16777215).toString(16);
    }

    // 背景图片
    if (bgImg) {
      let bgImgObj = new Image();
      bgImgObj.crossOrigin = "Anonymous";
      bgImgObj.src = bgImg;
      bgImgObj.onload = async () => {
        ctx.drawImage(bgImgObj, 0, 0, width, height);
        createText();
        createImg();
      };

      // 加载失败
      bgImgObj.onerror = () => {
        reject("加载背景图片失败");
      };

      return;
    }

    // 无背景图片,随机生成背景颜色
    let bgColor = createColor();
    ctx.fillStyle = bgColor;
    ctx.fillRect(0, 0, width, height);
    createText();
    createImg();
  });
}

// 64 => imgfile
export function dataURLtoFile(base64Url, filename) {
  return new Promise((res) => {
    if (typeof base64Url !== "string" || !base64Url) {
      return;
    }
    let arr = base64Url.split(",");
    if (!isArrayLength(arr)) {
      return "";
    }
    try {
      let mime = arr[0]?.match(/:(.*?);/)[1] || "";
      let bstr = window.atob(arr[1]);
      let n = bstr.length;
      let u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      res({
        file_: new File([u8arr], filename, { type: mime }),
      });
    } catch (err) {
      Toast(err);
      saveError(err);
    }
  });
}

// 是否是pc
export function isPc() {
  if (!isBrowser) {
    const { platformType } = useUserInfoStore();
    return platformType == 1;
  }
  if (isDev) {
    // 可视区宽度
    let clientWidth = document.documentElement.clientWidth;
    if (clientWidth < 500) {
      return false;
    }
  }
  if (/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
    return false;
  }
  return true;
}

// 处理时间
// 返回示例 4个月前 (11/12) 21:41
// 传入time示例  2022-03-11T16:23:12.764Z
export function myTime(time, type = 0) {
  if (!time) {
    return "---";
  }
  let date = "";
  if (type === 0 || type === 2) {
    date = new Date(time);
  }
  // 获取当前时间戳
  let now = new Date().getTime();
  // 获取传入时间戳
  let old = new Date(time).getTime();
  // 获取时间差
  let diff = now - old;
  // 返回 **前
  let oneYear = 60 * 60 * 24 * 365 * 1000;
  let arr = [
    60 * 1000,
    60 * 60 * 1000,
    60 * 60 * 24 * 1000,
    60 * 60 * 24 * 7 * 1000,
    60 * 60 * 24 * 30 * 1000,
    oneYear,
  ];
  let str_obj = ["分钟", "小时", "天", "周", "月", "年"];
  let str = "";

  if (diff >= oneYear) {
    return Math.floor(diff / oneYear) + "年前";
  }
  for (let i = 0; i < arr.length; i++) {
    if (diff < arr[i]) {
      // 向上取整
      if (i == 0) {
        return "1分钟前";
      }
      str = Math.ceil(diff / arr[i - 1]) + str_obj[i - 1] + "前";
      break;
    }
  }

  return str;
}

export function getFlyColor(frequency) {
  let result = "";
  colorsFly.find(({ min, label }) => {
    if (frequency >= min) {
      result = label;
      return true;
    }
  });

  return result;
}

// ctrl-f效果
export function handleCtrlF(
  content = "",
  f_dom = "body",
  c_dom = ["strong", "h1", "h2", "h3"]
) {
  if (content.length > 0 && Array.isArray(c_dom) && c_dom.length > 0) {
    content = content.toLowerCase();
    // 先要清除原来的
    let els = $(".active-ctrl-mo-bg");
    if (els.length > 0) {
      for (let i = 0; i < els.length; i++) {
        let content = els.eq(i).html();
        // replaceWith() 方法用指定的 HTML 内容或元素替换被选元素
        els.eq(i).replaceWith(content);
      }
    }

    // 绑定新的
    for (let i = 0; i < c_dom.length; i++) {
      let allDomTop = [];
      let domStr = c_dom[i];
      let regExp = new RegExp(content, "g");

      $(f_dom + " " + domStr).each(function () {
        let html = $(this).html().toLowerCase();
        //不包含隐藏的HTML
        if (content.indexOf(content) >= 0 && html.indexOf(content) >= 0) {
          if (
            !content.includes("search-height-light-class") ||
            $(this)[0].children.length == 0
          ) {
            let id = "wxj-" + createId();
            if ($(this) && $(this).offset()) {
              let obj = {
                id,
              };

              allDomTop.push(obj);

              // 替换为高亮节点
              let newHtml = html.replace(
                regExp,
                `<font id='${id}' class="active-ctrl-mo-bg">` +
                  content +
                  "</font>"
              );
              $(this).html(newHtml);
            }
          }
        }
      });
    }
  }
}

export function debounce(fn, time = 200) {
  let timeout = null; // 创建一个标记用来存放定时器的返回值
  return function () {
    clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
    timeout = setTimeout(() => {
      // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话，就不会执行 fn 函数
      fn.apply(this, arguments);
    }, time);
  };
}

// 获取可视区宽高
export function getViewportSize() {
  const width =
    window.innerWidth ||
    document.documentElement.clientWidth ||
    document.body.clientWidth;

  const height =
    window.innerHeight ||
    document.documentElement.clientHeight ||
    document.body.clientHeight;

  return { width, height };
}

/**
 * 生成水印背景图片函数useWatermarkBg()
 * deg: 旋转角度
 * text: 文字
 * fontSize: 字体大小
 * gap: 间距
 */
export async function useWatermarkBg(props = {}) {
  let {
    deg = 45,
    text = "blog",
    fontSize = 24,
    gap = 80,
    fillStyle = "rgba(0, 0, 0, 0.3)",
  } = props;
  // 创建一个 canvas
  const canvas = document.createElement("canvas");
  const devicePixelRatio = window.devicePixelRatio || 1;
  // 设置字体大小
  fontSize = fontSize * devicePixelRatio;
  const font = fontSize + "px serif";
  const ctx = canvas.getContext("2d");
  // 获取文字宽度
  ctx.font = font;
  const { width } = ctx.measureText(text);
  const canvasSize = Math.max(100, width) + gap * devicePixelRatio;
  canvas.width = canvasSize;
  canvas.height = canvasSize;
  ctx.translate(canvas.width / 2, canvas.height / 2);
  // 旋转 45 度让文字变倾斜
  ctx.rotate((Math.PI / 180) * -deg);
  ctx.fillStyle = fillStyle;
  ctx.font = font;
  ctx.textAlign = "center";
  ctx.textBaseline = "middle";
  // 将文字画出来
  ctx.fillText(text, 0, 0);
  let file = await dataURLtoFile(canvas.toDataURL(), createId());
  let url = getObjectURL(file.file_);
  return {
    url,
    size: canvasSize,
    styleSize: canvasSize / devicePixelRatio,
  };
}

export function filterTime(timestamp) {
  if (!isToNumber(timestamp)) {
    return "---";
  }
  return klDateFormat(timestamp);
}

// 文件限制
export function fileLimit(file, options = {}) {
  let { maxSize } = options;
  let size = file.size / 1024;

  // 判断大小
  if (maxSize) {
    if (size > maxSize) {
      return Promise.resolve(`文件大小不能超过${maxSize}KB`);
    }
  }

  return Promise.resolve("");
}

// 判断是否是谷歌内核
export function isWebkit() {
  if (!isBrowser) return;
  return navigator.userAgent.indexOf("WebKit") > -1;
}

// 判断是否为数字
export function isNumber(data) {
  return typeof data === "number" && !isNaN(data);
}

// 系统延迟函数
export function winSleep(fn) {
  if (!isBrowser) return;
  if (window?.requestIdleCallback) {
    window.requestIdleCallback(fn);
  } else if (window?.requestAnimationFrame) {
    window.requestAnimationFrame(fn);
  } else {
    Toast(new Error("浏览器不支持requestIdleCallback与requestAnimationFrame"));
  }
}

/**
 * 数组按照下面的顺序排序返回
 * oldArr 原数组
 * sortArr 排序数组
 * key  排序key
 * ***/
export function sortArray(oldArr, sortArr, key) {
  if (!Array.isArray(oldArr) || !Array.isArray(sortArr) || !key) {
    console.warn("sortArray传入参数错误");
    return oldArr;
  }
  let obj = {};
  // 创建基本数组
  sortArr.forEach((item) => {
    obj[item] = [];
  });

  oldArr.forEach((item) => {
    obj[item[key]].push(item);
  });
  let newArr = [];
  sortArr.forEach((item) => {
    newArr = [...newArr, ...obj[item]];
  });

  return newArr;
}

// 定义一个处理时间的函数
// 参数说明
// 当传入参数是时间戳  记得转化类型 time-0
// datetime = new Date()
// datetime.setTime(time)  // 主要利用这个方法
export function moment(time, length) {
  // 当传入参数是 2021-11-23T06:29:11.699Z 或 时间戳
  let datetime = null;
  if (time !== -1) {
    datetime = new Date(time);
  } else {
    datetime = new Date();
  }
  let year = datetime.getFullYear();
  let month = datetime.getMonth() + 1;
  let date = datetime.getDate();
  let hour = datetime.getHours();
  if (hour <= 9) {
    hour = "0" + hour;
  }
  let minute = datetime.getMinutes();
  if (minute <= 9) {
    minute = "0" + minute;
  }
  let second = datetime.getSeconds();
  if (second <= 9) {
    second = "0" + second;
  }

  if (length === "year") {
    return year + "年" + month + "月" + date + "日";
  }

  if (length == 3) {
    return year + "-" + month + "-" + date;
  }
  if (length === "array") {
    return [year, month, date, hour, minute, second];
  }
  // let mseconds = datetime.getMilliseconds();
  return (
    year + "-" + month + "-" + date + " " + hour + ":" + minute + ":" + second
  ); //+"."+mseconds;
}

// 获取具体星期几
export function getWeek(year, month, day) {
  let week = new Date(`${year}/${month}/${day} 00:00:00`).getDay();
  return week == 0 ? 7 : week;
}

// 获取一个月多少天
export function getDaysInMonth(year, month) {
  // 注意：JavaScript中月份是从0开始的，但此函数接受从1开始的月份
  // 因此，我们需要将月份减1以匹配Date对象的预期
  var date = new Date(year, month - 1 + 1, 0); // 下一个月的第一天，但日设置为0会自动回退到本月的最后一天
  // getDate() 方法返回 Date 对象中月的“日”字段（1-31）
  return date.getDate();
}

// 获取pickerOptions
export function getPickerOptions(arr = [1, 2, 3, 4, 5, 6, 8]) {
  const oneDay = 24 * 3600 * 1000;
  const obj = {
    1: {
      text: "今日",
      value: () => {
        const [yyyy, MM, dd] = klDateFormat(Date.now(), "[yyyy,MM,dd]");
        const end = new Date(`${yyyy}/${MM}/${dd} 23:59:59`);
        const start = new Date(`${yyyy}/${MM}/${dd} 00:00:00`);
        return [start, end];
      },
    },
    2: {
      text: "本周",
      value: () => {
        const [yyyy, MM, dd] = klDateFormat(Date.now(), "[yyyy,MM,dd]");
        let week = getWeek(yyyy, MM, dd);
        const currentTime = new Date(`${yyyy}-${MM}-${dd} 23:59:59`).getTime();
        const start = new Date(
          klDateFormat(currentTime + 1000 - 3600 * 1000 * 24 * week)
        );
        const end = new Date(
          klDateFormat(currentTime + (7 - week) * 3600 * 24 * 1000)
        );

        return [start, end];
      },
    },
    3: {
      text: "本月",
      value: () => {
        let [yyyy, MM] = klDateFormat(Date.now(), "[yyyy,MM]");
        const str2 = `${yyyy}/${MM}/01 00:00:00`;
        const start = new Date(str2);
        const end = new Date(
          klDateFormat(
            new Date(str2).getTime() +
              3600 * 1000 * 24 * getDaysInMonth(yyyy, MM) -
              1
          )
        );
        return [start, end];
      },
    },
    4: {
      text: "最近半年",
      value: () => {
        const end = new Date();
        const start = new Date(
          klDateFormat(end.getTime() - 3600 * 1000 * 24 * 180)
        );
        return [start, end];
      },
    },
    5: {
      text: "上月",
      value: () => {
        let [yyyy, MM] = klDateFormat(Date.now(), "[yyyy,MM]");
        if (+MM === 1) {
          yyyy = yyyy - 1;
          MM = 12;
        } else {
          MM = MM - 1;
        }

        const str2 = `${yyyy}/${MM}/01 00:00:00`;
        const start = new Date(str2);
        const end = new Date(
          klDateFormat(
            new Date(str2).getTime() +
              3600 * 1000 * 24 * getDaysInMonth(yyyy, MM) -
              1
          )
        );
        return [start, end];
      },
    },
    6: {
      text: "今明两月",
      value: () => {
        let [yyyy, MM] = klDateFormat(Date.now(), "[yyyy,MM]");
        const next_yyyy = MM == 12 ? yyyy - 0 + 1 : yyyy;
        const next_MM = MM == 12 ? 1 : MM - 0 + 1;
        const str2 = `${next_yyyy}/${next_MM}/01 00:00:00`;
        const start = new Date(`${yyyy}/${MM}/01 00:00:00`);
        const end = new Date(
          klDateFormat(
            new Date(str2).getTime() +
              3600 * 1000 * 24 * getDaysInMonth(next_yyyy, next_MM) -
              1
          )
        );
        return [start, end];
      },
    },
    7: {
      text: "今年",
      value: () => {
        let [yyyy] = klDateFormat(Date.now(), "[yyyy]");
        const start = new Date(`${yyyy}/01/01 00:00:00`);
        const end = new Date();
        return [start, end];
      },
    },
    8: {
      text: "过去两月", // 上个月和这个月
      value: () => {
        let [yyyy, MM] = klDateFormat(Date.now(), "[yyyy,MM]");
        const str1 = `${yyyy}/${MM}/01 00:00:00`;
        const str2 = `${MM === 1 ? yyyy - 1 : yyyy}/${
          MM === 1 ? 12 : MM - 1
        }/01 00:00:00`;
        const start = new Date(str2);
        const end = new Date(
          klDateFormat(
            new Date(str1).getTime() +
              3600 * 1000 * 24 * getDaysInMonth(yyyy, MM) -
              1
          )
        );

        return [start, end];
      },
    },
    9: {
      text: "一周前", // 起始时间2020年
      value: () => {
        let [yyyy, MM, dd] = klDateFormat(
          Date.now() - 7 * oneDay,
          "[yyyy,MM,dd]"
        );
        const str1 = `2020/01/01 00:00:00`;
        const str2 = `${yyyy}/${MM}/${dd} 23:59:59`;
        const start = new Date(str1);
        const end = new Date(klDateFormat(str2));

        return [start, end];
      },
    },
    10: {
      text: "一个月前", // 起始时间2020年
      value: () => {
        let [yyyy, MM, dd] = klDateFormat(
          Date.now() - 30 * oneDay,
          "[yyyy,MM,dd]"
        );
        const str1 = `2020/01/01 00:00:00`;
        const str2 = `${yyyy}/${MM}/${dd} 23:59:59`;
        const start = new Date(str1);
        const end = new Date(klDateFormat(str2));

        return [start, end];
      },
    },
    11: {
      text: "去年至今",
      value: () => {
        let [yyyy] = klDateFormat(Date.now(), "[yyyy]");
        const start = new Date(`${yyyy - 1}/01/01 00:00:00`);
        const end = new Date();
        return [start, end];
      },
    },
  };
  return arr.map((item) => obj[item]);
}

/**
 * 通过年月获取当月的天数
 * y 年
 * m 月
 * **/
export function getMonthDays(y, m) {
  let d = new Date(y, m, 0);
  return d.getDate();
}

// 全局的获取label的方法
export function getLabel(arr, value) {
  return arr.find((item) => item.value == value)?.label || "--";
}

// 判断文件大小
export function isFileSize(file, size = 10) {
  if (!file || !file.size) {
    return "文件不存在";
  }

  let fileSize = file.size / 1024 / 1024;
  if (fileSize > size) {
    return `文件大小不能超过${size}M`;
  }
}

// 判断文件类型
export function isFileType(file, arr) {
  let name = file.name?.toLowerCase() || "";
  let type = name.substring(name.lastIndexOf(".") + 1);

  if (!type) {
    return "文件类型不存在";
  }
  if (!arr.includes(type)) {
    return `文件类型不正确,请上传${arr.join("、")}类型的文件`;
  }
}

// 专门用于e-form使用配置数据生成formData
export function createFormData(arr) {
  const obj = {};
  arr.forEach((item) => {
    obj[item.modelName] = item.value;
  });
  return obj;
}

// 不上报的错误
const baiArr = [
  "ResizeObserver loop completed with undelivered notifications.",
];

// 错误上报 saveError()
export function saveError(message) {
  if (isDev) return;
  if (message) {
    // 手动触发的错误上报
    captureError({
      message,
      des: "user_handler",
    });
    return;
  }

  // onErrorCaptured = (err) => {
  //     // vue错误上报
  //     captureError({
  //         message: err?.message,
  //         des: 'onErrorCaptured',
  //     })
  // }

  window.addEventListener("error", function (event) {
    // js执行错误
    captureError({
      message: event.message,
      des: "error",
    });
  });

  window.addEventListener("unhandledrejection", function (event) {
    let type = getType(event.reason);
    let message = event.reason;
    if (["array", "object"].includes(type)) {
      message = JSON.stringify(event.reason);
    }

    if (event.reason.message?.indexOf("dynamically imported module") > -1) {
      // TODO: 检测到新版本，是否立即更新？
      // if (window.confirm('检测到新版本，是否立即更新？')) {
      //     window.location.reload()
      // } else {
      //     window.location.reload()
      // }
    }
    // promise错误
    captureError({
      message,
      des: "promise错误 - unhandledrejection",
    });
  });

  function captureError({ message, des }) {
    let message_type = getType(message);
    switch (message_type) {
      case "array":
        message = JSON.stringify(message);
        break;
      case "object":
        message = JSON.stringify(message);
        break;
      case "error":
        message = message.toString();
        break;
      case "promiserejectionevent":
        message = message.reason.toString();
        break;
      default:
        break;
    }

    // 错误类型
    const type = 6;

    const name = `博客项目【nuxt3】错误上报(${isPc() ? "PC端" : "移动端"})`;

    if (!message || baiArr.includes(message)) return;
    let errStore = getSessionStorage("errStore") || [];
    let index = errStore.findIndex((item) => item.message === message);
    // 防止重复上报
    if (index > -1) return;
    setSessionStorage("errStore", [...errStore, { message }]);
    // 上报错误信息 img上报
    let url = VueRouteruseRoute()?.fullPath || "未知链接";
    const { userdata } = useUserInfoStore();
    let { _id } = userdata?.value || {};
    let params = {
      type,
      name,
      content: message,
      url,
      des,
    };

    if (_id) {
      params.user_id = _id;
    }
    let img = new Image();
    img.src = `${BASE_URL}/page_point?${paramsJoin(params)}`;
  }
}

export function preHandlerImgs(htmlString) {
  if (typeof window === "undefined") {
    return htmlString;
  }
  if (!htmlString) {
    return "";
  }
  const parser = new DOMParser();
  const doc = parser.parseFromString(htmlString, "text/html");
  const imgListArr = doc.body.querySelectorAll("img");
  for (let i = 0; i < imgListArr.length; i++) {
    let item = imgListArr[i];
    // 获取图片的src
    let src = item.src;
    if(!src){
      continue
    }

    // 获取data-src
    let dataSrc = item.getAttribute("data-src");
    if (dataSrc) {
      // 由于table的多次渲染，这儿需要终止
      continue;
    }

    // 重新设置图片的宽高
    $(item).attr("data-src", src);
    let arr = src.split("~");
    arr = arr.filter((item) => !isNaN(+item));
    if (Array.isArray(arr)) {
      let len = arr.length;
      if (len === 3) {
        let maxWidth = 960;
        let width = +arr[1];
        let height = +arr[2];
        if (isNaN(width) || isNaN(height)) {
          $(item).css({
            opacity: 1,
          });
          continue;
        }

        item.src = "";
        if (width > maxWidth) {
          let scale = maxWidth / width;
          width = maxWidth;
          height = height * scale;
        }
        $(item).css({
          opacity: 0,
          width: width + "px",
          height: height + "px",
        });
      } else {
        $(item).css({
          opacity: 1,
        });
      }
    } else {
      $(item).css({
        opacity: 1,
      });
    }
  }

  const serializer = new XMLSerializer();
  const modifiedHtml = serializer.serializeToString(doc.body);
  // 移除外层的body
  let div = document.createElement("div");
  div.innerHTML = modifiedHtml;
  return div.innerHTML;
}

export async function download(url, name) {
  try {
    getIndexDBJS([
      {
        js: "http://47.108.195.190:5000/netdist/StreamSaver-1728968748124~1~.js",
      },
    ])
      .then(() => {
        const fileName = name || url.split("/").pop();
        const fileStream = streamSaver.createWriteStream(fileName);
        fetch(url).then((res) => {
          const readableStream = res.body;
          if (window.WritableStream && readableStream.pipeTo) {
            return readableStream.pipeTo(fileStream);
          }
          window.writer = fileStream.getWriter();
          res.body
            .getReader()
            .read()
            .then((res) =>
              res.done ? writer.close() : writer.write(res.value).then(pump)
            );
        });
      })
      .catch((err) => {
        Toast(err);
      });
  } catch (error) {
    Toast(error);
  }
}

// 中间处理方法
// item 行数据
// key 行数据中的key
// limitType 限制的类型
// defaultVal 默认值
export function middleFn({ item = {}, val, limitType = [], defaultVal, row }) {
  if (defaultVal === undefined) {
    Toast("请设置默认值");
    return defaultVal;
  }
  const { modelName, label } = item || {};
  const tipLabel = modelName || label;
  const valType = getType(val);
  if (!limitType.includes(valType)) {
    Toast(`${tipLabel}的${valType}必须是${limitType.join("、")}类型`);
    return defaultVal;
  }
  if (["function", "asyncfunction"].includes(valType)) {
    return val(row);
  }

  const defaultValType = getType(defaultVal);
  if (defaultValType === "boolean") {
    if (defaultVal & !isExist(val)) {
      return defaultVal;
    }
    return !!val;
  }
  return val;
}

// 所有缓存接口数据
const allData = {}

// 用于缓存接口数据，防止重复发起相同请求
// expire_time    -1 取消原来的缓存    0 缓存，并不设时长   大于0 缓存多少毫秒
// update_save_time 是否更新保存时间 只有  expire_time大于0时生效 
export async function cacheFetch(api, { params = {}, expire_time = 60*1000,update_save_time = true } = {}) {
  if (expire_time === -1) {
    delete allData[key]
  }
  const key = joinParams(api, params)
  const { data, save_time } = allData[key] || {}

  const dataType = getType(data)
  if (dataType === 'promise') {
    try {
      return await data
    } catch (err) {
      delete allData[key]
      return Promise.reject(err)
    }
  }

  const currrntTime = Date.now()
  if (![undefined, null].includes(data)) {
    if (expire_time === 0 || (expire_time > 0 && expire_time + save_time >= currrntTime)) {
      if(update_save_time){
        allData[key].save_time = currrntTime
      }
      return data
    }
  }

  try {
    allData[key] = apis[api](params)
    const res = await allData[key]
    allData[key] = {
      data: res,
      save_time: currrntTime,
    }
    return res
  } catch (err) {
    delete allData[key]
    return Promise.reject(err)
  }
}
